From 1bb4ad8e20a326bec0c845149980211d1f69869e Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Mon, 9 Apr 2007 12:05:26 +0100 Subject: [PATCH] hvm ioemu: Avoid accessing invalid pseudophysical addresses in HVM guest's memory map. Signed-off-by: Keir Fraser --- tools/ioemu/target-i386-dm/exec-dm.c | 25 ++----- tools/ioemu/vl.c | 100 +++++++++++++++++++-------- tools/ioemu/vl.h | 15 ---- 3 files changed, 76 insertions(+), 64 deletions(-) diff --git a/tools/ioemu/target-i386-dm/exec-dm.c b/tools/ioemu/target-i386-dm/exec-dm.c index d992f987e1..4f56a2d715 100644 --- a/tools/ioemu/target-i386-dm/exec-dm.c +++ b/tools/ioemu/target-i386-dm/exec-dm.c @@ -128,12 +128,10 @@ char *logfilename = "/tmp/qemu.log"; FILE *logfile; int loglevel; - #ifdef MAPCACHE pthread_mutex_t mapcache_mutex; #endif - void cpu_exec_init(CPUState *env) { CPUState **penv; @@ -427,21 +425,10 @@ int iomem_index(target_phys_addr_t addr) return 0; } -static inline int paddr_is_ram(target_phys_addr_t addr) -{ - /* Is this guest physical address RAM-backed? */ -#if defined(CONFIG_DM) && (defined(__i386__) || defined(__x86_64__)) - return ((addr < HVM_BELOW_4G_MMIO_START) || - (addr >= HVM_BELOW_4G_MMIO_START + HVM_BELOW_4G_MMIO_LENGTH)); -#else - return (addr < ram_size); -#endif -} - #if defined(__i386__) || defined(__x86_64__) #define phys_ram_addr(x) (qemu_map_cache(x)) #elif defined(__ia64__) -#define phys_ram_addr(x) (phys_ram_base + (x)) +#define phys_ram_addr(x) ((addr < ram_size) ? (phys_ram_base + (x)) : NULL) #endif extern unsigned long *logdirty_bitmap; @@ -481,16 +468,15 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val); l = 1; } - } else if (paddr_is_ram(addr)) { + } else if ((ptr = phys_ram_addr(addr)) != NULL) { /* Writing to RAM */ - ptr = phys_ram_addr(addr); memcpy(ptr, buf, l); if (logdirty_bitmap != NULL) { /* Record that we have dirtied this frame */ unsigned long pfn = addr >> TARGET_PAGE_BITS; if (pfn / 8 >= logdirty_bitmap_size) { - fprintf(logfile, "dirtying pfn %x >= bitmap size %x\n", - pfn, logdirty_bitmap_size * 8); + fprintf(logfile, "dirtying pfn %lx >= bitmap " + "size %lx\n", pfn, logdirty_bitmap_size * 8); } else { logdirty_bitmap[pfn / HOST_LONG_BITS] |= 1UL << pfn % HOST_LONG_BITS; @@ -518,9 +504,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, stb_raw(buf, val); l = 1; } - } else if (paddr_is_ram(addr)) { + } else if ((ptr = phys_ram_addr(addr)) != NULL) { /* Reading from RAM */ - ptr = phys_ram_addr(addr); memcpy(buf, ptr, l); } else { /* Neither RAM nor known MMIO space */ diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index 494ceb6e2a..2b11eb18d9 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -5894,7 +5894,32 @@ void suspend(int sig) suspend_requested = 1; } -#if defined(__i386__) || defined(__x86_64__) +#if defined(MAPCACHE) + +#if defined(__i386__) +#define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */ +#define MCACHE_BUCKET_SHIFT 16 +#elif defined(__x86_64__) +#define MAX_MCACHE_SIZE 0x1000000000 /* 64GB max for x86_64 */ +#define MCACHE_BUCKET_SHIFT 20 +#endif + +#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT) + +#define BITS_PER_LONG (sizeof(long)*8) +#define BITS_TO_LONGS(bits) \ + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] +#define test_bit(bit,map) \ + (!!((map)[(bit)/BITS_PER_LONG] & (1UL << ((bit)%BITS_PER_LONG)))) + +struct map_cache { + unsigned long paddr_index; + uint8_t *vaddr_base; + DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>PAGE_SHIFT); +}; + static struct map_cache *mapcache_entry; static unsigned long nr_buckets; @@ -5928,6 +5953,44 @@ static int qemu_map_cache_init(void) return 0; } +static void qemu_remap_bucket(struct map_cache *entry, + unsigned long address_index) +{ + uint8_t *vaddr_base; + unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT]; + unsigned int i, j; + + if (entry->vaddr_base != NULL) { + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); + if (errno) { + fprintf(logfile, "unmap fails %d\n", errno); + exit(-1); + } + } + + for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++) + pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i; + + vaddr_base = xc_map_foreign_batch(xc_handle, domid, PROT_READ|PROT_WRITE, + pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT); + if (vaddr_base == NULL) { + fprintf(logfile, "xc_map_foreign_batch error %d\n", errno); + exit(-1); + } + + entry->vaddr_base = vaddr_base; + entry->paddr_index = address_index; + + for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i += BITS_PER_LONG) { + unsigned long word = 0; + j = ((i + BITS_PER_LONG) > (MCACHE_BUCKET_SIZE >> PAGE_SHIFT)) ? + (MCACHE_BUCKET_SIZE >> PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG; + while (j > 0) + word = (word << 1) | !(pfns[i + --j] & 0xF0000000UL); + entry->valid_mapping[i / BITS_PER_LONG] = word; + } +} + uint8_t *qemu_map_cache(target_phys_addr_t phys_addr) { struct map_cache *entry; @@ -5939,34 +6002,12 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr) entry = &mapcache_entry[address_index % nr_buckets]; - if (entry->vaddr_base == NULL || entry->paddr_index != address_index) { - /* We need to remap a bucket. */ - uint8_t *vaddr_base; - unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT]; - unsigned int i; - - if (entry->vaddr_base != NULL) { - errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); - if (errno) { - fprintf(logfile, "unmap fails %d\n", errno); - exit(-1); - } - } + if (entry->vaddr_base == NULL || entry->paddr_index != address_index || + !test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping)) + qemu_remap_bucket(entry, address_index); - for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++) - pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i; - - vaddr_base = xc_map_foreign_batch( - xc_handle, domid, PROT_READ|PROT_WRITE, - pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT); - if (vaddr_base == NULL) { - fprintf(logfile, "xc_map_foreign_batch error %d\n", errno); - exit(-1); - } - - entry->vaddr_base = vaddr_base; - entry->paddr_index = address_index;; - } + if (!test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping)) + return NULL; last_address_index = address_index; last_address_vaddr = entry->vaddr_base; @@ -6001,7 +6042,8 @@ void qemu_invalidate_map_cache(void) mapcache_unlock(); } -#endif + +#endif /* defined(MAPCACHE) */ int main(int argc, char **argv) { diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index 4ef250f766..635a86b071 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -161,21 +161,6 @@ extern FILE *logfile; #define MAPCACHE -#if defined(__i386__) -#define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */ -#define MCACHE_BUCKET_SHIFT 16 -#elif defined(__x86_64__) -#define MAX_MCACHE_SIZE 0x1000000000 /* 64GB max for x86_64 */ -#define MCACHE_BUCKET_SHIFT 20 -#endif - -#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT) - -struct map_cache { - unsigned long paddr_index; - uint8_t *vaddr_base; -}; - uint8_t *qemu_map_cache(target_phys_addr_t phys_addr); void qemu_invalidate_map_cache(void); -- 2.30.2